﻿using System;
using System.Runtime.CompilerServices;
using System.Threading;

namespace Hsenl {
    internal abstract class HTaskBody : IHTaskBody {
        private volatile int _version = HTask.MinVersion;
        private volatile bool _isDisposed;

        public int Version => this._version;
        public abstract HTaskStatus Status { get; }
        public abstract bool IsCompleted { get; }
        public Action MoveNext { get; }
        public IAsyncStateMachine StateMachine { get; set; }
        public bool IsDisposed => this._isDisposed;

        private void Run() {
            this.StateMachine!.MoveNext();
        }

        public HTaskBody() {
            this.MoveNext = this.Run;
        }

        public virtual void Init() {
            this._isDisposed = false;
        }

        public abstract void GetResult();

        public abstract void SetResult();

        public abstract void SetException(Exception e);

        public abstract void Abort();

        public abstract void OnCompleted(Action continuation);

        public abstract void UnsafeOnCompleted(Action continuation);
        
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected void IncrementVersion() {
            Interlocked.Increment(ref this._version);
            Interlocked.CompareExchange(ref this._version, HTask.MinVersion, HTask.MaxVersion);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void ReturnBody() {
            HTaskBodyPool.ReturnBody(this);
        }

        public virtual void Dispose() {
            if (this._isDisposed)
                return;

            this._isDisposed = true;
            this.StateMachine = null;
        }
    }

    internal abstract class HTaskBody<T> : IHTaskBody<T> {
        private volatile int _version = HTask.MinVersion;
        private volatile bool _isDisposed;

        public int Version => this._version;
        public abstract HTaskStatus Status { get; }
        public abstract bool IsCompleted { get; }
        public Action MoveNext { get; }
        public IAsyncStateMachine StateMachine { get; set; }
        public bool IsDisposed => this._isDisposed;

        private void Run() {
            this.StateMachine!.MoveNext();
        }

        public HTaskBody() {
            this.MoveNext = this.Run;
        }

        public virtual void Init() {
            this._isDisposed = false;
        }

        public abstract T GetResult();

        public abstract void SetResult(T result);

        public abstract void SetException(Exception e);

        public abstract void Abort();

        public abstract void OnCompleted(Action continuation);

        public abstract void UnsafeOnCompleted(Action continuation);
        
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected void IncrementVersion() {
            Interlocked.Increment(ref this._version);
            Interlocked.CompareExchange(ref this._version, HTask.MinVersion, HTask.MaxVersion);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void ReturnBody() {
            HTaskBodyPool.ReturnBody(this);
        }

        public virtual void Dispose() {
            if (this._isDisposed)
                return;

            this._isDisposed = true;
            this.StateMachine = null;
        }
    }
}